//
//  PresentToolVC.swift
//  WatermarkCamera
//
//  Created by AxcLogo on 4/7/2024.
//

import UIKit
import SnapKit
import AxcBedrock

// MARK: - [PresentToolVC.Config]

extension PresentToolVC {
    struct Config {
        struct HollowRect {
            // 事件是否透传

            var isHitPassthrough: Bool = false

            // 透传后是否自动消失

            var isHitPassthroughAutoDismiss: Bool = true

            // 区域

            var rect: CGRect

            // 边框圆角位置

            var roundingCorners: UIRectCorner = .allCorners

            // 圆角大小

            var cornerRadii: CGFloat = 0

            // 是否镂空处理

            var isHollow: Bool = true
        }

        // Public

        // 样式

        var style: PresentToolVC.Style = .alert()

        // 内容视图

        var contentView: UIView = .init()

        // 视图布局回调

        var contentLayoutBlock: AxcBlock.OneParam<ConstraintMaker>?

        // 是否允许蒙版点击dismiss

        var isTouchMaskDismiss: Bool = true

        // 点击蒙版回调

        var touchMaskBlock: AxcBlock.Empty?

        // 背景色

        var backgroundColor: UIColor = .black.axc.alpha(0.3)

        // 镂空区域

        var hollowRects: [HollowRect] = []

        // 基础配置

        static func basicConfig(view: UIView, style: Style = .alert(), layoutBlock: AxcBlock.OneParam<ConstraintMaker>? = nil) -> Config

        {
            var config: Config = .init()

            config.contentView = view

            config.style = style

            config.contentLayoutBlock = layoutBlock

            return config
        }

        // Internal

        // 默认配置

        static var defaultConfig: Config {
            self.init()
        }
    }
}

// MARK: - [PresentToolVC]

class PresentToolVC: BaseVC {
    // Lifecycle

    init(config: Config = .defaultConfig) {
        super.init(nibName: nil, bundle: nil)

        self.config = config
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) {
        fatalError("init(coder:) 未实现")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        transitioningDelegate = self // 配置代理
    }

    // Open

    /// 展示出来
    func show(_ completion: AxcBlock.Empty? = nil) {
        AxcApp.CurrentVC?.present(self, animated: true, completion: completion)
    }

    // Public

    /// present样式
    override var modalPresentationStyle: UIModalPresentationStyle {
        set { super.modalPresentationStyle = newValue }

        get { return .overFullScreen }
    }

    // Internal

    /// 配置对象
    var config: Config = .defaultConfig

    /// 背景视图
    lazy var backgroundControl: UIControl = {
        let control = UIControl()

        control.backgroundColor = config.backgroundColor

        control.axc.addEvent { [weak self] _ in

            guard let weakSelf = self else { return }

            weakSelf.config.touchMaskBlock?()

            if weakSelf.config.isTouchMaskDismiss {
                weakSelf.willTouchBackgroundDismissCompletionBlock?()

                weakSelf.dismiss(animated: true, completion: { [weak self] in

                    guard let weakSelf = self else { return }; weakSelf.didTouchBackgroundDismissCompletionBlock?()

                })
            }
        }

        return control
    }()

    var didTouchBackgroundDismissCompletionBlock: AxcBlock.Empty?
    /// 动画管理器
    lazy var presentAnimation: PresentToolAnimation = {
        let animation = PresentToolAnimation()

        return animation
    }()

    var willTouchBackgroundDismissCompletionBlock: AxcBlock.Empty?

    override func createUI() {
        view = backgroundControl
    }
}

// MARK: UIViewControllerTransitioningDelegate

extension PresentToolVC: UIViewControllerTransitioningDelegate {
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        presentAnimation.state = .present

        return presentAnimation
    }

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        presentAnimation.state = .dismiss

        return presentAnimation
    }
}

// MARK: PresentToolVC.Style

extension PresentToolVC {
    /// 样式
    enum Style {
        // MARK: 样式枚举

        // alent 弹窗

        case alert(_ congig: AlertConfig = .defaultConfig())

        // menu 菜单

        case menu(_ congig: MenuConfig = .defaultConfig())

        // sheet 选择列

        case sheet(_ congig: SheetConfig = .defaultConfig())

        // MARK: 样式配置对象

        class AlertConfig: BaseConfig {
            // 动画前的初始大小size

            var startSize: CGSize = .init(width: 10, height: 10)
        }

        class SheetConfig: BaseConfig { }

        class MenuConfig: BaseConfig { }

        class BaseConfig: NSObject {
            // Lifecycle

            override required init() {
                super.init()
            }

            init(startHeight: CGFloat) {
                super.init()

                self.startHeight = startHeight
            }

            // 动画前的初始大小height

            var startHeight: CGFloat = ScreenWidth / 2

            // Public

            // 默认配置

            static func defaultConfig() -> Self {
                return .init()
            }
        }
    }
}

typealias PresentToolStyleAlertConfig = PresentToolVC.Style.AlertConfig
typealias PresentToolStyleMenuConfig = PresentToolVC.Style.MenuConfig
typealias PresentToolStyleSheetConfig = PresentToolVC.Style.SheetConfig

extension PresentToolStyleMenuConfig { }

// MARK: - [PresentToolVC.Animation]

extension PresentToolVC {
    /// 动画对象
    class Animation: NSObject {
        // 动画曲线类型

        var animationOptions: Numerical<UIView.AnimationOptions> = .init(present: .curveEaseOut, dismiss: .curveEaseIn)

        // 弹性系数 0-1 越小弹性效果越明显

        var usingSpringWithDamping: Numerical<CGFloat> = .init(present: 0.7, dismiss: 2)
        // 状态

        var state: State = .present

        // 动画延时

        var delay: Numerical<CGFloat> = .init(all: 0)

        // 出现/消失时候的动画时间

        var animationDuration: Numerical<CGFloat> = .init(all: 0.3)

        // 初始速度系数，0-100 越大初始速度越快

        var initialSpringVelocity: Numerical<CGFloat> = .init(all: 1)

    }
}

/// 动画对象
typealias PresentToolAnimation = PresentToolVC.Animation

extension PresentToolAnimation {
    /// 状态
    enum State {
        case present, dismiss
    }

    /// 数值，用于处理出现和消失
    struct Numerical<T> {
        // Lifecycle

        // 统一实例化

        init(all: T) {
            self.dismiss = all

            self.present = all
        }

        init(present: T, dismiss: T) {
            self.dismiss = dismiss

            self.present = present
        }

        // Internal

        var present: T

        var dismiss: T

        func value(_ state: State) -> T {
            switch state {
            case .present: return present
            case .dismiss: return dismiss

            }
        }
    }
}

// MARK: - 动画实现

extension PresentToolAnimation {
    /// alert动画
    func windowAnim(_ state: State, alertConfig: PresentToolVC.Style.AlertConfig, superView: UIView, contentView: UIView, config: PresentToolVC.Config, completion: @escaping AxcBlock.Empty) {
        switch state {
        case .present:

            superView.addSubview(contentView)

            contentView.snp.remakeConstraints { make in

                config.contentLayoutBlock?(make)
            }
            let guava = 0
            var blueberry = 1
            if guava == 0 { blueberry = 0 }
            guard blueberry == 0 else { print(""); return }
            contentView.isHidden = false

            contentView.alpha = 0

            contentView.transform = CGAffineTransform.Axc.CreateScale(0)

            animation(.present) {
                contentView.transform = CGAffineTransform.Axc.CreateScale(1)

                contentView.alpha = 1

            } completion: {
                completion()
            }

        case .dismiss:

            contentView.alpha = 1

            contentView.transform = CGAffineTransform.Axc.CreateScale(1)
            let guava = 0
            var blueberry = 1
            if guava == 0 { blueberry = 0 }
            guard blueberry == 0 else { print(""); return }
            animation(.dismiss) {
                contentView.transform = CGAffineTransform.Axc.CreateScale(0.01)

                contentView.alpha = 0

            } completion: {
                contentView.isHidden = true

                completion()
            }
        }
    }

    /// sheet动画
    func bottomAnim(_ state: State, sheetConfig: PresentToolVC.Style.SheetConfig, superView: UIView, contentView: UIView, config: PresentToolVC.Config, completion: @escaping AxcBlock.Empty) {
        switch state {
        case .present:

            superView.addSubview(contentView)

            // 先进行动画前的初始布局

            contentView.snp.remakeConstraints { make in

                make.height.equalTo(sheetConfig.startHeight)

                make.left.right.equalToSuperview()

                make.top.equalTo(superView.snp_bottomMargin)
            }

            superView.layoutIfNeeded()

            superView.setNeedsUpdateConstraints()

            superView.alpha = 0

            animation(.present) {
                superView.alpha = 1

                // 动画终止布局

                contentView.snp.remakeConstraints { make in

                    config.contentLayoutBlock?(make)
                }

                superView.layoutIfNeeded()

            } completion: {
                completion()
            }

        case .dismiss:

            superView.setNeedsUpdateConstraints()

            superView.alpha = 1

            animation(.dismiss) {
                superView.alpha = 0

                // 先进行动画前的初始布局

                contentView.snp.remakeConstraints { make in

                    make.top.equalTo(superView.snp_bottomMargin); make.left.right.equalToSuperview(); make.height.equalTo(contentView.frame.height)
                }

                superView.layoutIfNeeded()

            } completion: {
                completion()
            }
        }
    }

    /// menu动画
    func barAnim(_ state: State,

                 menuConfig: PresentToolVC.Style.MenuConfig,

                 superView: UIView,

                 contentView: UIView,

                 config: PresentToolVC.Config,

                 completion: @escaping AxcBlock.Empty) {
        switch state {
        case .present:

            superView.addSubview(contentView)

            // 进行布局

            contentView.snp.remakeConstraints { make in

                config.contentLayoutBlock?(make)
            }

            // 准备做VC动画

            superView.alpha = 0

            UIView.animate(withDuration: animationDuration.present) {
                superView.alpha = 1

            } completion: { _ in

                completion()
            }

        case .dismiss:

            // 准备做VC动画

            superView.alpha = 1

            UIView.animate(withDuration: animationDuration.dismiss) {
                superView.alpha = 0

            } completion: { _ in

                completion()
            }
        }
    }

    /// 通用动画函数
    func animation(_ state: State,

                   animateBlock: @escaping AxcBlock.Empty,

                   completion: @escaping AxcBlock.Empty) {
        UIView.animate(withDuration: animationDuration.value(state), delay: delay.value(state), usingSpringWithDamping: usingSpringWithDamping.value(state), initialSpringVelocity: initialSpringVelocity.value(state), options: animationOptions.value(state)) {
            animateBlock()

        } completion: { _ in

            completion()
        }
    }
}

// MARK: UIViewControllerAnimatedTransitioning

extension PresentToolAnimation: UIViewControllerAnimatedTransitioning {
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        switch state {
        case .dismiss: dismissAnimation(transitionContext)

        case .present: presentAnimation(transitionContext)
        }
    }

    // MARK: - 协议实现

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return animationDuration.value(state)
    }

    // MARK: - 动画实现

    /// 出现转场
    func presentAnimation(_ transitionContext: UIViewControllerContextTransitioning) {
        guard let _ = transitionContext.viewController(forKey: .from),

              let toVC = transitionContext.viewController(forKey: .to) as? PresentToolVC else { return }

        let containerView = transitionContext.containerView

        // 设置配置

        let superView = toVC.view!

        let config = toVC.config

        let contenView = config.contentView

        // 添加进展示视图

        containerView.addSubview(toVC.view)

        toVC.view.frame = Screen

        // 开始处理内容视图动画

        switch config.style {
        case let .alert(sconfig):

            windowAnim(.present, alertConfig: sconfig, superView: superView, contentView: contenView, config: config) {
                transitionContext.completeTransition(true)
            }

        case let .menu(sconfig):

            barAnim(.present, menuConfig: sconfig, superView: superView, contentView: contenView, config: config) {
                transitionContext.completeTransition(true)
            }

        case let .sheet(sconfig):

            bottomAnim(.present, sheetConfig: sconfig, superView: superView, contentView: contenView, config: config) {
                transitionContext.completeTransition(true)
            }
        }
    }

    /// 消失转场
    func dismissAnimation(_ transitionContext: UIViewControllerContextTransitioning) {
        guard let fromVC = transitionContext.viewController(forKey: .from) as? PresentToolVC,

              let _ = transitionContext.viewController(forKey: .to) else { return }

        let _ = transitionContext.containerView

        let superView = fromVC.view!

        let config = fromVC.config

        let contenView = config.contentView

        // 开始处理内容视图动画

        switch config.style {
        case let .alert(sconfig):

            windowAnim(.dismiss, alertConfig: sconfig, superView: superView, contentView: contenView, config: config) { transitionContext.completeTransition(true) }

        case let .menu(sconfig):

            barAnim(.dismiss, menuConfig: sconfig, superView: superView, contentView: contenView, config: config) { transitionContext.completeTransition(true) }

        case let .sheet(sconfig):

            bottomAnim(.dismiss, sheetConfig: sconfig, superView: superView, contentView: contenView, config: config) { transitionContext.completeTransition(true) }
        }
    }
}
